package cn.jinbyte.core.utils;


import lombok.experimental.UtilityClass;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.Assert;
import org.springframework.util.NumberUtils;

import java.math.BigDecimal;
import java.math.BigInteger;

/**
 * 数字工具类
 *
 * @author jinty
 * @since 2024/12/1
 */
@UtilityClass
public class NumUtils extends NumberUtils {

    private static BigInteger decodeBigInteger(String value) {
        int radix = 10;
        int index = 0;
        boolean negative = false;
        if (value.startsWith("-")) {
            negative = true;
            ++index;
        }

        if (!value.startsWith("0x", index) && !value.startsWith("0X", index)) {
            if (value.startsWith("#", index)) {
                ++index;
                radix = 16;
            } else if (value.startsWith("0", index) && value.length() > 1 + index) {
                ++index;
                radix = 8;
            }
        } else {
            index += 2;
            radix = 16;
        }

        BigInteger result = new BigInteger(value.substring(index), radix);
        return negative ? result.negate() : result;
    }

    private static boolean isHexNumber(String value) {
        int index = value.startsWith("-") ? 1 : 0;
        return value.startsWith("0x", index) || value.startsWith("0X", index) || value.startsWith("#", index);
    }

    public static Number parse(String text, Class<?> targetClass) {

        Assert.isTrue(Number.class.isAssignableFrom(targetClass), "Text must not be null");
        Assert.notNull(text, "Text must not be null");
        Assert.notNull(targetClass, "Target class must not be null");
        String trimmed = StringUtils.trim(text);
        if (Byte.class == targetClass) {
            return isHexNumber(trimmed) ? Byte.decode(trimmed) : Byte.valueOf(trimmed);
        } else if (Short.class == targetClass) {
            return isHexNumber(trimmed) ? Short.decode(trimmed) : Short.valueOf(trimmed);
        } else if (Integer.class == targetClass) {
            return isHexNumber(trimmed) ? Integer.decode(trimmed) : Integer.valueOf(trimmed);
        } else if (Long.class == targetClass) {
            return isHexNumber(trimmed) ? Long.decode(trimmed) : Long.valueOf(trimmed);
        } else if (BigInteger.class == targetClass) {
            return isHexNumber(trimmed) ? decodeBigInteger(trimmed) : new BigInteger(trimmed);
        } else if (Float.class == targetClass) {
            return Float.valueOf(trimmed);
        } else if (Double.class == targetClass) {
            return Double.valueOf(trimmed);
        } else if (BigDecimal.class != targetClass && Number.class != targetClass) {
            throw new IllegalArgumentException("Cannot convertForm String [" + text + "] to target class [" + targetClass.getName() + "]");
        } else {
            return new BigDecimal(trimmed);
        }
    }
}
